菜单组件:组件结构与Props类型定义
本节搭建 Menu 组件的基础结构——文件组织、Props 类型定义、以及如何正确地与 Element Plus 的 el-menu 进行属性透传。核心原则是:Menu 组件作为 el-menu 的增强包装器,应该透传 el-menu 支持的所有属性和事件,同时添加自己的增强功能。
文件结构
src/components/menu/
├── menu.vue # 顶层菜单容器
├── sub-menu.vue # 子菜单组件(递归)
├── menu-item.vue # 菜单项组件
├── types.ts # 类型定义
└── use-menu.ts # 工具方法 composable
text
Props 类型定义
Menu 组件的 Props 继承 el-menu 的属性,同时添加自定义属性:
// menu.vue
import type { MenuProps } from 'element-plus'
interface MenuCustomProps {
data: AppRouteMenuItem[] // 菜单数据
iconProps?: IconOptions // 图标样式配置
}
type VMenuProps = Partial<MenuProps> & MenuCustomProps
typescript
使用 Partial<MenuProps> 使所有 el-menu 的属性变为可选,因为组件内部会提供合理的默认值。
属性透传策略
方式一:v-bind 整体透传
<el-menu v-bind="menuProps">
vue
使用 computed 将自定义 props 和 el-menu props 分离:
const { data, iconProps, ...menuProps } = toRefs(props)
typescript
方式二:useAttrs 全量透传
const attrs = useAttrs()
typescript
<el-menu v-bind="{ ...menuProps, ...attrs }">
vue
useAttrs 可以捕获所有未在 defineProps 中声明的属性和事件,实现全量透传。
基础模板结构
<!-- menu.vue -->
<template>
<div class="flex">
<!-- Logo 插槽 -->
<slot name="icon" />
<!-- 菜单区域 -->
<el-menu v-bind="menuProps">
<template v-for="item in filteredMenus" :key="item.meta?.key">
<MenuItem
v-if="!menuHasChildren(item)"
:data="item"
/>
<SubMenu
v-if="menuHasChildren(item)"
:data="item"
:collapse="menuProps.collapse"
/>
</template>
</el-menu>
</div>
</template>
vue
注意 MenuItem 和 SubMenu 使用两个独立的 v-if(而非 v-if/v-else),因为中间可能有其他结构。
默认值设置
const props = withDefaults(defineProps<VMenuProps>(), {
data: () => [],
mode: 'vertical',
collapse: false,
ellipsis: false,
})
typescript
ellipsis: false 禁用 el-menu 在水平模式下自动省略超出宽度的菜单项。
provide 注入图标配置
Menu 组件通过 provide 向所有子组件注入图标样式:
provide('iconProps', {
style: props.iconProps?.style ?? { fontSize: '22px' },
class: props.iconProps?.class ?? 'mr-3',
})
typescript
子组件通过 inject 获取:
const iconProps = inject<IconOptions>('iconProps')
typescript
这样图标大小和间距只需在 Menu 组件上配置一次,所有子组件自动继承。
背景颜色兼容处理
// 同时设置 props 和 CSS 变量
const menuStyle = computed(() => ({
'--el-menu-bg-color': props.bgColor ?? 'transparent',
backgroundColor: props.bgColor ?? 'transparent',
}))
typescript
<el-menu :style="menuStyle">
vue
这样无论用户使用旧版还是新版 Element Plus,背景颜色都能正确设置。
本节小结
- 文件结构:Menu、SubMenu、MenuItem 三个组件 + types.ts + use-menu.ts。
- Props 类型:
Partial<MenuProps>继承el-menu的所有属性,添加data等自定义属性。 - 属性透传:通过
computed分离自定义 props 和el-menuprops,使用v-bind透传。 - provide/inject:图标样式通过
provide注入,子组件inject获取,一次配置全局生效。
↑